package ace.module.upms.core.impl.service.impl;

import ace.module.common.api.model.input.AppIdListInput;
import ace.module.upms.api.model.dto.UpmsOrganizationDto;
import ace.module.upms.api.model.input.UpmsOrgBindAccountInput;
import ace.module.upms.core.impl.dao.entity.UpmsOrganization;
import ace.module.upms.core.impl.dao.entity.UpmsOrganizationAccount;
import ace.module.upms.core.impl.manager.UpmsOrganizationAccountManager;
import ace.module.upms.core.impl.manager.UpmsOrganizationManager;
import ace.module.upms.core.impl.manager.cache.UpmsOrganizationCacheManager;
import ace.module.upms.core.impl.service.UpmsOrganizationService;
import java.util.AbstractMap.SimpleEntry;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @author caspar
 * @date 2023/8/18 17:42
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class UpmsOrganizationServiceImpl implements UpmsOrganizationService {

  private final UpmsOrganizationCacheManager upmsOrganizationCacheManager;
  private final UpmsOrganizationManager upmsOrganizationManager;
  private final UpmsOrganizationAccountManager upmsOrganizationAccountManager;


  @Override
  public Map<Long, List<UpmsOrganizationDto>> getAccountIdAndOrgMapByUpmsAppIdAndIamAccountIdIn(Long upmsAppId, List<Long> iamAccountIds) {
    Map<Long, List<UpmsOrganizationDto>> result = new HashMap<>();
    for (Long iamAccountId : iamAccountIds) {
      List<UpmsOrganizationDto> organizationDtos = this.getByUpmsApIdAndIamAccountId(upmsAppId, iamAccountId);
      result.put(iamAccountId, organizationDtos);
    }
    return result;
  }

  @Override
  public List<UpmsOrganizationDto> getByUpmsApIdAndIamAccountId(Long upmsAppId, Long iamAccountId) {
    List<UpmsOrganization> result = upmsOrganizationCacheManager.getByUpmsApIdAndIamAccountId(upmsAppId, iamAccountId);
    return this.upmsOrganizationManager.convertToEntityDto(result);
  }

  @Override
  public void saveOrgAccountRelation(AppIdListInput<UpmsOrgBindAccountInput> inputs) {
    Long upmsAppId = inputs.getAppId();

    List<Long> queryOrgIds = inputs.getData().stream()
        .map(UpmsOrgBindAccountInput::getUpmsOrgId)
        .collect(Collectors.toList());

    List<Long> queryIamAccountIds = inputs.getData().stream()
        .map(UpmsOrgBindAccountInput::getIamAccountId)
        .collect(Collectors.toList());

    List<SimpleEntry<Long, Long>> queryOrgIdAndAccountIds = inputs.getData().stream()
        .map(p -> new SimpleEntry<>(p.getUpmsOrgId(), p.getIamAccountId()))
        .collect(Collectors.toList());

    List<UpmsOrganization> existQueryAllOrgs = upmsOrganizationManager.getByUpmsAppIdAndIdInAndDeleteFlagIsFalse(upmsAppId, queryOrgIds);

    List<UpmsOrganizationAccount> existAllQueryOrgAccounts = this.upmsOrganizationAccountManager.getByUpmsAppIdAndIamAccountIdIn(upmsAppId, queryIamAccountIds);

    List<UpmsOrganizationAccount> newUpmsOrganizationAccounts = inputs.getData()
        .stream()
        .filter(p -> this.upmsOrganizationManager.anyMatch(existQueryAllOrgs, p.getUpmsOrgId()))
        .filter(p -> this.upmsOrganizationAccountManager.noneMatch(existAllQueryOrgAccounts, p.getUpmsOrgId(), p.getIamAccountId()))
        .map(input -> this.upmsOrganizationAccountManager.build(upmsAppId, input.getUpmsOrgId(), input.getIamAccountId()))
        .collect(Collectors.toList());

    List<Long> deleteUpmsOrganizationAccountIds = existAllQueryOrgAccounts.stream()
        .filter(p -> !this.upmsOrganizationManager.anyMatch(existQueryAllOrgs, p.getUpmsOrgId()))
        .filter(p -> !this.upmsOrganizationAccountManager.anyMatch(existAllQueryOrgAccounts, queryOrgIdAndAccountIds))
        .map(UpmsOrganizationAccount::getId)
        .collect(Collectors.toList());

    this.upmsOrganizationAccountManager.insertNewAndDeleteByIdIn(newUpmsOrganizationAccounts, deleteUpmsOrganizationAccountIds);
  }
}
